use crate::src::struct_and_type::{
    HashTable, HashTableEntry, HashTableEqualFunc, HashTableHashFunc, HashTableIterator,
    HashTableKey, HashTableKeyFreeFunc, HashTablePair, HashTableValue, HashTableValueFreeFunc,
    _HashTablePair,
};

extern "C" {
    fn malloc(_: u64) -> *mut ();
    fn calloc(_: u64, _: u64) -> *mut ();
    fn free(_: *mut ());
}
static mut hash_table_primes: [u32; 24] = [ 193 as u32, 389 as u32, 769 as u32, 1543 as u32, 3079 as u32, 6151 as u32, 12289 as u32, 24593 as u32, 49157 as u32, 98317 as u32, 196613 as u32, 393241 as u32, 786433 as u32, 1572869 as u32, 3145739 as u32, 6291469 as u32, 12582917 as u32, 25165843 as u32, 50331653 as u32, 100663319 as u32, 201326611 as u32, 402653189 as u32, 805306457 as u32, 1610612741 as u32,
];
static mut hash_table_num_primes: u32 = 0;
extern "C" fn hash_table_allocate_table(mut hash_table: *mut HashTable) -> i32 {
    let mut new_table_size: u32 = 0;
    if (unsafe { (*hash_table).prime_index }) < (unsafe { hash_table_num_primes }) {
        new_table_size = unsafe { hash_table_primes[(*hash_table).prime_index as usize] };
    } else {
        new_table_size = (unsafe { (*hash_table).entries }).wrapping_mul(10 as i32 as u32);
    }
    (unsafe { (*hash_table).table_size = new_table_size });
    (unsafe {
        (*hash_table).table = calloc(
            (*hash_table).table_size as u64,
            ::core::mem::size_of::<*mut HashTableEntry>() as u64,
        ) as *mut *mut HashTableEntry
    });
    return ((unsafe { (*hash_table).table }) != core::ptr::null_mut() as *mut *mut HashTableEntry)
        as i32;
}
extern "C" fn hash_table_free_entry(
    mut hash_table: *mut HashTable,
    mut entry: *mut HashTableEntry,
) {
    let mut pair: *mut HashTablePair = 0 as *mut HashTablePair;
    pair = unsafe { &mut (*entry).pair };
    if unsafe { ((*hash_table).key_free_func).is_some() } {
        (unsafe { ((*hash_table).key_free_func).expect("non-null function pointer")((*pair).key) });
    }
    if unsafe { ((*hash_table).value_free_func).is_some() } {
        (unsafe {
            ((*hash_table).value_free_func).expect("non-null function pointer")((*pair).value)
        });
    }
    (unsafe { free(entry as *mut ()) });
}
#[no_mangle]
pub extern "C" fn hash_table_new(
    mut hash_func: HashTableHashFunc,
    mut equal_func: HashTableEqualFunc,
) -> *mut HashTable {
    let mut hash_table: *mut HashTable = 0 as *mut HashTable;
    hash_table = (unsafe { malloc(::core::mem::size_of::<HashTable>() as u64) }) as *mut HashTable;
    if hash_table.is_null() {
        return 0 as *mut HashTable;
    }
    (unsafe { (*hash_table).hash_func = hash_func });
    (unsafe { (*hash_table).equal_func = equal_func });
    (unsafe { (*hash_table).key_free_func = None });
    (unsafe { (*hash_table).value_free_func = None });
    (unsafe { (*hash_table).entries = 0 as u32 });
    (unsafe { (*hash_table).prime_index = 0 as u32 });
    if hash_table_allocate_table(hash_table) == 0 {
        (unsafe { free(hash_table as *mut ()) });
        return 0 as *mut HashTable;
    }
    return hash_table;
}
#[no_mangle]
pub extern "C" fn hash_table_free(mut hash_table: *mut HashTable) {
    let mut rover: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut next: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut i: u32 = 0;
    i = 0 as u32;
    while i < (unsafe { (*hash_table).table_size }) {
        rover = unsafe { *((*hash_table).table).offset(i as isize) };
        while !rover.is_null() {
            next = unsafe { (*rover).next };
            hash_table_free_entry(hash_table, rover);
            rover = next;
        }
        i = i.wrapping_add(1);
        i;
    }
    (unsafe { free((*hash_table).table as *mut ()) });
    (unsafe { free(hash_table as *mut ()) });
}
#[no_mangle]
pub extern "C" fn hash_table_register_free_functions(
    mut hash_table: *mut HashTable,
    mut key_free_func: HashTableKeyFreeFunc,
    mut value_free_func: HashTableValueFreeFunc,
) {
    (unsafe { (*hash_table).key_free_func = key_free_func });
    (unsafe { (*hash_table).value_free_func = value_free_func });
}
extern "C" fn hash_table_enlarge(mut hash_table: *mut HashTable) -> i32 {
    let mut old_table: *mut *mut HashTableEntry = 0 as *mut *mut HashTableEntry;
    let mut old_table_size: u32 = 0;
    let mut old_prime_index: u32 = 0;
    let mut rover: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut pair: *mut HashTablePair = 0 as *mut HashTablePair;
    let mut next: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut index: u32 = 0;
    let mut i: u32 = 0;
    old_table = unsafe { (*hash_table).table };
    old_table_size = unsafe { (*hash_table).table_size };
    old_prime_index = unsafe { (*hash_table).prime_index };
    (unsafe { (*hash_table).prime_index = ((*hash_table).prime_index).wrapping_add(1) });
    (unsafe { (*hash_table).prime_index });
    if hash_table_allocate_table(hash_table) == 0 {
        (unsafe { (*hash_table).table = old_table });
        (unsafe { (*hash_table).table_size = old_table_size });
        (unsafe { (*hash_table).prime_index = old_prime_index });
        return 0;
    }
    i = 0 as u32;
    while i < old_table_size {
        rover = unsafe { *old_table.offset(i as isize) };
        while !rover.is_null() {
            next = unsafe { (*rover).next };
            pair = unsafe { &mut (*rover).pair };
            index = (unsafe {
                ((*hash_table).hash_func).expect("non-null function pointer")((*pair).key)
            })
            .wrapping_rem(unsafe { (*hash_table).table_size });
            (unsafe { (*rover).next = *((*hash_table).table).offset(index as isize) });
            let fresh0 = unsafe { &mut (*((*hash_table).table).offset(index as isize)) };
            *fresh0 = rover;
            rover = next;
        }
        i = i.wrapping_add(1);
        i;
    }
    (unsafe { free(old_table as *mut ()) });
    return 1;
}
#[no_mangle]
pub extern "C" fn hash_table_insert(
    mut hash_table: *mut HashTable,
    mut key: HashTableKey,
    mut value: HashTableValue,
) -> i32 {
    let mut rover: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut pair: *mut HashTablePair = 0 as *mut HashTablePair;
    let mut newentry: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut index: u32 = 0;
    if (unsafe { (*hash_table).entries })
        .wrapping_mul(3 as i32 as u32)
        .wrapping_div(unsafe { (*hash_table).table_size })
        > 0 as u32
    {
        if hash_table_enlarge(hash_table) == 0 {
            return 0;
        }
    }
    index = (unsafe { ((*hash_table).hash_func).expect("non-null function pointer")(key) })
        .wrapping_rem(unsafe { (*hash_table).table_size });
    rover = unsafe { *((*hash_table).table).offset(index as isize) };
    while !rover.is_null() {
        pair = unsafe { &mut (*rover).pair };
        if (unsafe {
            ((*hash_table).equal_func).expect("non-null function pointer")((*pair).key, key)
        }) != 0
        {
            if unsafe { ((*hash_table).value_free_func).is_some() } {
                (unsafe {
                    ((*hash_table).value_free_func).expect("non-null function pointer")(
                        (*pair).value,
                    )
                });
            }
            if unsafe { ((*hash_table).key_free_func).is_some() } {
                (unsafe {
                    ((*hash_table).key_free_func).expect("non-null function pointer")((*pair).key)
                });
            }
            (unsafe { (*pair).key = key });
            (unsafe { (*pair).value = value });
            return 1;
        }
        rover = unsafe { (*rover).next };
    }
    newentry =
        (unsafe { malloc(::core::mem::size_of::<HashTableEntry>() as u64) }) as *mut HashTableEntry;
    if newentry.is_null() {
        return 0;
    }
    (unsafe { (*newentry).pair.key = key });
    (unsafe { (*newentry).pair.value = value });
    (unsafe { (*newentry).next = *((*hash_table).table).offset(index as isize) });
    let fresh1 = unsafe { &mut (*((*hash_table).table).offset(index as isize)) };
    *fresh1 = newentry;
    (unsafe { (*hash_table).entries = ((*hash_table).entries).wrapping_add(1) });
    (unsafe { (*hash_table).entries });
    return 1;
}
#[no_mangle]
pub extern "C" fn hash_table_lookup(
    mut hash_table: *mut HashTable,
    mut key: HashTableKey,
) -> HashTableValue {
    let mut rover: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut pair: *mut HashTablePair = 0 as *mut HashTablePair;
    let mut index: u32 = 0;
    index = (unsafe { ((*hash_table).hash_func).expect("non-null function pointer")(key) })
        .wrapping_rem(unsafe { (*hash_table).table_size });
    rover = unsafe { *((*hash_table).table).offset(index as isize) };
    while !rover.is_null() {
        pair = unsafe { &mut (*rover).pair };
        if (unsafe {
            ((*hash_table).equal_func).expect("non-null function pointer")(key, (*pair).key)
        }) != 0
        {
            return unsafe { (*pair).value };
        }
        rover = unsafe { (*rover).next };
    }
    return core::ptr::null_mut();
}
#[no_mangle]
pub extern "C" fn hash_table_remove(mut hash_table: *mut HashTable, mut key: HashTableKey) -> i32 {
    let mut rover: *mut *mut HashTableEntry = 0 as *mut *mut HashTableEntry;
    let mut entry: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut pair: *mut HashTablePair = 0 as *mut HashTablePair;
    let mut index: u32 = 0;
    let mut result: i32 = 0;
    index = (unsafe { ((*hash_table).hash_func).expect("non-null function pointer")(key) })
        .wrapping_rem(unsafe { (*hash_table).table_size });
    result = 0;
    rover =
        (unsafe { &mut *((*hash_table).table).offset(index as isize) }) as *mut *mut HashTableEntry;
    while !(unsafe { *rover }).is_null() {
        pair = unsafe { &mut (**rover).pair };
        if (unsafe {
            ((*hash_table).equal_func).expect("non-null function pointer")(key, (*pair).key)
        }) != 0
        {
            entry = unsafe { *rover };
            (unsafe { *rover = (*entry).next });
            hash_table_free_entry(hash_table, entry);
            (unsafe { (*hash_table).entries = ((*hash_table).entries).wrapping_sub(1) });
            (unsafe { (*hash_table).entries });
            result = 1;
            break;
        } else {
            rover = unsafe { &mut (**rover).next };
        }
    }
    return result;
}
#[no_mangle]
pub extern "C" fn hash_table_num_entries(mut hash_table: *mut HashTable) -> u32 {
    return unsafe { (*hash_table).entries };
}
#[no_mangle]
pub extern "C" fn hash_table_iterate(
    mut hash_table: *mut HashTable,
    mut iterator: *mut HashTableIterator,
) {
    let mut chain: u32 = 0;
    (unsafe { (*iterator).hash_table = hash_table });
    (unsafe { (*iterator).next_entry = 0 as *mut HashTableEntry });
    chain = 0 as u32;
    while chain < (unsafe { (*hash_table).table_size }) {
        if !(unsafe { *((*hash_table).table).offset(chain as isize) }).is_null() {
            (unsafe { (*iterator).next_entry = *((*hash_table).table).offset(chain as isize) });
            (unsafe { (*iterator).next_chain = chain });
            break;
        } else {
            chain = chain.wrapping_add(1);
            chain;
        }
    }
}
#[no_mangle]
pub extern "C" fn hash_table_iter_has_more(mut iterator: *mut HashTableIterator) -> i32 {
    return ((unsafe { (*iterator).next_entry }) != core::ptr::null_mut() as *mut HashTableEntry)
        as i32;
}
#[no_mangle]
pub extern "C" fn hash_table_iter_next(mut iterator: *mut HashTableIterator) -> HashTablePair {
    let mut current_entry: *mut HashTableEntry = 0 as *mut HashTableEntry;
    let mut hash_table: *mut HashTable = 0 as *mut HashTable;
    let mut pair: HashTablePair = {
        let mut init = _HashTablePair {
            key: core::ptr::null_mut(),
            value: core::ptr::null_mut(),
        };
        init
    };
    let mut chain: u32 = 0;
    hash_table = unsafe { (*iterator).hash_table };
    if (unsafe { (*iterator).next_entry }).is_null() {
        return pair;
    }
    current_entry = unsafe { (*iterator).next_entry };
    pair = unsafe { (*current_entry).pair };
    if !(unsafe { (*current_entry).next }).is_null() {
        (unsafe { (*iterator).next_entry = (*current_entry).next });
    } else {
        chain = (unsafe { (*iterator).next_chain }).wrapping_add(1 as i32 as u32);
        (unsafe { (*iterator).next_entry = 0 as *mut HashTableEntry });
        while chain < (unsafe { (*hash_table).table_size }) {
            if !(unsafe { *((*hash_table).table).offset(chain as isize) }).is_null() {
                (unsafe { (*iterator).next_entry = *((*hash_table).table).offset(chain as isize) });
                break;
            } else {
                chain = chain.wrapping_add(1);
                chain;
            }
        }
        (unsafe { (*iterator).next_chain = chain });
    }
    return pair;
}
extern "C" fn run_static_initializers_hash_table() {
    (unsafe {
        hash_table_num_primes = (::core::mem::size_of::<[u32; 24]>() as u64)
            .wrapping_div(::core::mem::size_of::<i32>() as u64)
            as u32
    });
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers_hash_table];
